<?php
/**
 * Created by PhpStorm.
 * User: eValor
 * Date: 2019-03-20
 * Time: 16:57
 */
namespace App\GameService;

use App\Enum\CardEnum;
use App\Model\GameType;
use App\WebSocket\WsBase;
use App\Common\AuthCommon;
use App\Common\GameCommon;
use App\Utility\BaseEnum;
use App\Utility\RedisTools;
use App\GameService\games\PlayHelp;
use App\Common\BaseComm;
use App\GameService\games\PlayBaiRen;
use App\Enum\SysEnum;
use EasySwoole\EasySwoole\Task\TaskManager;
use Swoole\Timer;
use App\Common\PlayCommon;

/**
 * Class Index
 *
 * @package App\WebSocket\Controller
 */
class Games extends WsBase
{

    // 定时器功能：
    public static $gameCommonTimer = array();

    protected $gameHandleObj = false;
    protected $allowGameIds = [101,102,112,103,111];

    // 游戏类
    protected $player_pipei_Timer = 0;

    // 匹配等待的定时器

    /**
     * 游戏大厅；验证成功进入游戏列表页面
     *
     * @return NULL
     */
    public function index()
    {
        return null;
    }
    
    
    /**
     * TODO 游戏大厅空协议处理
     */
    public function doCenter(){
        $loginFd = $this->paramsBean->getFd();
        BaseEnum::Logger('空心化协议处理： (doCenter) 异步清理数据  !!!! ', 'user-login');
        try {
            
            $userId = FALSE; // TODO 玩家信息验证
            $playerInfo = $this->LoginPlayUser($userId);
            if (!$playerInfo || $userId <= 0 ) { return FALSE; }
            
            //TODO 百人牛牛游戏房间列表上的用户FD清理
            $gameId = 105;
            $allUserFds = BaseComm::distMemoryFjListUser(105,FALSE);
            if (!empty($allUserFds) && isset($allUserFds[$userId])) {
                unset($allUserFds[$userId]);
                BaseComm::distMemoryFjListUser($gameId,TRUE,$allUserFds);   //TODO　写入房间列表FD
            }
            
            //TODO 停留在游戏大厅的FD放入内存中
            BaseComm::doLobbyInOrOut($userId, $loginFd,TRUE);               //TODO　写入大厅列表FD
            
            //TODO 其它操作（启动首页房间列表页定时更新在线玩家的功能）
        } catch (\Throwable $e) {
            BaseEnum::Logger("操作异常：" . $e->getMessage(), 'user-login');
            return TRUE;
        }
    }

    
    /**
     * TODO 玩家进入房间
     */
    public function play()
    {
        $gameOObject = $this->paramsBean->getGameObject();
        $gameName = '';
        $gameResult = [
            "gstart" => 0,
            "gameNo" => "",
            "gameInning"=> 1,
            "isFirst"=>1,
            "roomInfo" => [],
            "players" => []
        ];
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        $debugFlag = isset($data['debug']) ? intval($data['debug']) : 0;
        BaseEnum::Logger("实例：匹配开始[roomId={$gameRId}]) -> obj:" . json_encode($gameOObject), 'user-login');
        if (!$gameRId) {
            $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失",SysEnum::RETURN_MSG_LEVEL_1);
            return true;
        }
        
        $userid = FALSE; // TODO 玩家信息验证
        $playerInfo = $this->LoginPlayUser($userid);
        if (!$playerInfo || $userid <= 0 ) { return FALSE; }
        
        // 获取在线的游戏列表数据；
        try {
            $gameModel = new GameType();
            $gRoomInfo = $gameModel->getGameRoomDetail($gameRId); // 获取房间详细参数
            $gameID = isset($gRoomInfo["gameId"]) ? intval($gRoomInfo["gameId"]) : 0;
            $gameName = isset($gRoomInfo["gpKey"]) ? $gRoomInfo["gpKey"] : "";
            $roomLastPots = isset($gRoomInfo["smallPoints"]) ? floatval($gRoomInfo["smallPoints"]) : 0;     // 房间的携带分要求；
            $roomEveryPots = isset($gRoomInfo["everyPoints"]) ? floatval($gRoomInfo["everyPoints"]) : 0;    // 房间底分
            $totalJu = isset($gRoomInfo["playNumber"]) ? intval($gRoomInfo["playNumber"]) : 1;              // 房间底分
            
            //TODO 判断是否开放这个游戏
            if($gameID >0 && $this -> pullGameStatus($gameID,$playerInfo,FALSE) === FALSE){
                $this->ResError(BaseEnum::MSG_0XF5,"该游戏暂未开放，请重试", SysEnum::RETURN_MSG_LEVEL_2);           //重新刷新
                return TRUE;
            }
            if (empty($gRoomInfo) || $gameID <= 0 || !in_array($gameID, $this->allowGameIds,TRUE)) {
                throw new \Exception("获取房间信息异常", BaseEnum::MSG_0XF6);
            }
            
            $gamedata = FALSE;
            //TODO 查询当前玩家上局游戏是否已完成
            $gameStatus = BaseComm::popGameFinishING($userid,$gameID,$gamedata);
            BaseEnum::Logger("上局游戏：[房间ID={$gameRId}]) ->  result :" . json_encode([$gameStatus,$gamedata]), 'user-login');
            if ($gameStatus === TRUE && !empty($gamedata)) {
                throw new \Exception("检查到上一局游戏未结束，请稍后再试", BaseEnum::MSG_0XE0);
            }
            

            $username = isset($playerInfo["name"]) ? $playerInfo["name"] : "";
            $login_points = isset($playerInfo["points"]) ? floatval($playerInfo["points"]) : 0;

            /*
             * TODO 判断玩家是否掉线；
             * $playerInfo = AuthCommon::getLoginUser($loginFd);
             * $userid = isset($playerInfo["uid"]) ? intval($playerInfo["uid"]) :0 ;
             * if(empty($playerInfo) || $userid <= 0 || empty($username)){
             * $this-> ResError(BaseEnum::MSG_0XF7,"玩家未登录，或玩家已掉线请重试");
             * return true;
             * }
             */

            // 是否准入分
            if ($login_points <= 0 || $login_points < $roomLastPots || $roomEveryPots <= 0) {
                throw new \Exception("玩家游戏分达不到房间最低标准，退出房间!!", BaseEnum::MSG_0XF8);
            }
            // 写入玩家信息
            $wjInfo = array(
                "uid" => $userid,
                'name' => $username,
                "isNation" => isset($playerInfo['isNation']) ? intval($playerInfo['isNation']) : 0,     // 玩家身份信息
                "agentId" => isset($playerInfo['recUid']) ? intval($playerInfo['recUid']) : 0,          // 代理用户ID
                "lineCode" => $playerInfo['lineCode'] ?? "",                                            // 玩家代理标记
                "pstatus" => 0,     // 玩家操作状态
                "sex" => isset($playerInfo['gender']) ? intval($playerInfo['gender']) : 0, // 性别
                "head_id" => isset($playerInfo['head_url']) ? intval($playerInfo['head_url']) : 0, // 头像
                "fd" => $loginFd,
                "points" => $login_points,
                "seatNo" => - 1, // 默认座位为0
                "mainflag" => 0, // 标识为闲家，默认0
                "mutdotts" => 0, // 默认倍数；抢庄，下注共用
                "betmoney" => 0.00,
            );

            $allRecUids = FALSE; //下级玩家的代理ID列表
            // 查询是否有未开局房间；(等待开局，返回是否可以开)
            $getFreeRoom = GameCommon::joinXYRooms($gameRId, $gRoomInfo, $wjInfo, $allRecUids);
            $room_No = isset($getFreeRoom["roomNo"]) ? $getFreeRoom["roomNo"] : ""; // 房间编号内容

            // 通知在线的其它用户；有新玩家上线
            $players = isset($getFreeRoom['info']) ? $getFreeRoom['info'] : false; // 玩家信息；
            $players_fd = ! empty($players) ? array_column($players, 'fd', "uid") : false; // 玩家FD列表；要及时推着在线等用户；
            if (isset($getFreeRoom) && ! empty($getFreeRoom) && isset($getFreeRoom['ifOpen']) && intval($getFreeRoom['ifOpen']) > 0 && ! empty($getFreeRoom['info'])) {
                BaseEnum::Logger('匹配成功：可以开局---->>>加入房间成功', 'user-login');
                $gameResult["gstart"] = 1;  // 有开局，(自动匹配)直接进入；要写DB操作；
                $gameResult["gameNo"] = $room_No;
                //加入详细数据；
                $gameResult["roomInfo"] = array("gameId"=>$gameID,"everyPoints"=>$roomEveryPots,"smallPoints"=>$roomLastPots,"curInning"=> 1,"total"=>$totalJu); //默认为第一局
                
                /************************************需要开局插入DB的游戏**********************************/
                
                $gRoomInfo["users_num"] = sizeof($players);
                $gRoomInfo["users"] = $getFreeRoom['info'];         // 游戏数据
                $gRoomInfo["agentsIds"] = $allRecUids ?? FALSE ;     // 代理玩家ID列表
                
                $dbEx = GameCommon::createRoomsPlayinfo($gameRId, $room_No, $gRoomInfo, $userid);   // 房间落地写入DB并开始发牌
                BaseEnum::Logger('取内存数据：[ROOM]--->>>' . json_encode(BaseComm::distMemoryRooms($room_No, FALSE)), 'user-login');
                // 写入成功，游戏开始
                if ($dbEx === true) {
                    BaseEnum::Logger("房间成功写入DB：Games-(play)-，开始游戏[debug={$debugFlag}]---->>>" . $room_No, 'user-login');
                }
                
                //二八杠人员不够用时补位置（没有实际意义）
                $gameResult["players"] = $players; // 有开局，(自动匹配)直接进入；要写DB操作；
                
                // 匹配成功后才推送给用户；
                if (! empty($players_fd)) { // 所有玩家都通知：
                    AuthCommon::pushFrontWeb($players_fd, json_encode([ 'm' => BaseEnum::XYM_0X16, "data" => $gameResult ])); // 推送相同内容
                    Timer::after(2000 , function() use ($players_fd){
                        $notCards = []; 
                        for ($i = 1; $i <= 10; $i++) { $notCards[] = ["key"=> $i,"num"=> 0]; }
                        $pushdata2 = [ 'm' => BaseEnum::XYM_0X25, "data" =>  $notCards];
                        AuthCommon::pushFrontWeb($players_fd, json_encode($pushdata2));                 //TODO 数据清零操作
                    });
                    
                }
                
                //游戏开始(asycStartGame)
                if (!$gameOObject || empty($gameOObject) || (!empty($gameOObject) && isset($gameOObject -> baseGameName) && $gameOObject -> baseGameName != $gameName)) {
                    $gameOObject = BaseEnum::getClassObject($gameName, false);           // 创建对象；
                    BaseEnum::Logger('实例化为空：新实例化一个操作；-->>>' . json_encode(['gName'=> $gameName,"obj"=> $gameOObject]), 'user-login');
                }
                if (!empty($gameOObject)) {
                    BaseEnum::Logger('实例化：变更Name (getGameObject)--->>>' . json_encode($gameOObject), 'user-login');
                    BaseEnum::Logger("开始进入互动：Games-(play)-getClassObject，[{$gameName}]---->>>" . json_encode($gameOObject), 'user-login');
                    if (! empty($gameOObject) && method_exists($gameOObject, "asycStartGame")) {
                        
                        // 启动游戏操作
                        $gameOObject->setGameStatus("P-" .CardEnum::GAME_STEP_0); // 设置游戏状态；
                        BaseEnum::Logger('实例化对象：' . json_encode($gameOObject), 'user-login');
                        BaseEnum::Logger("开始进入互动：Games-(play)-getClassObject，[{$gameName}]---->>>" . $room_No, 'user-login');
                        
                        $gameOObject -> asycStartGame($room_No, $gameRId, $gRoomInfo);
                    }
                } else {
                    BaseEnum::Logger("互动失败：Games-(play)-getClassObject，[{$gameName}]----失败!!!!" . json_encode($gameOObject), 'user-login');
                }                
            } else {
                /* $res = []; //列表中人数不够加入机器人
                $robotFile = EASYSWOOLE_ROOT.'/Robot/playQZNN.php';
                @exec("php {$robotFile}",$res);
                BaseEnum::Logger("执行系统函数：Games-(play)-System，[{$robotFile}]----执行".json_encode($res), 'user-login'); */
                
                
                //TODO 启动机器人等待
                $this->joinIntoRobots($gameRId,$loginFd,$userid,$gRoomInfo,$gameOObject);
                
                //TODO 进入等待(等待匹配其它玩家)
                $this->waitStartTimeOut($gameRId, $loginFd,$userid,$gRoomInfo);
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：玩家上桌失败[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
            $this->ResError($e->getCode(), $e->getMessage(),SysEnum::RETURN_MSG_LEVEL_1);
        }
        return true;
    }

    
    
    /**
     * TODO 继续下一步指定操作完
     * TO:如抢庄动画执行完；发送指令到服务器，开启下注功能
     * TO:参数提交：m=0x09; d.gameNo=游戏局号，type=1 默认抢庄>>>下注;
     */
    public function doNextStep()
    {
        $loginFd = $this->paramsBean->getFd();
        $gameOObject = $this->paramsBean->getGameObject();
        BaseEnum::Logger('实例化：整体 (doNextStep)--->>>' . json_encode($gameOObject), 'user-login');
        $pdata = $this->paramsBean->getData(true);
        $gameId = isset($pdata['gameId']) ? intval($pdata['gameId']) : 1;   // 游戏ID值；
        $gameNo = isset($pdata['gameNo']) ? $pdata['gameNo'] : "";          // 游戏号
        $type = isset($pdata['type']) ? intval($pdata['type']) : 1;         // 操作类型；
        $getUix = $this->paramsBean->getUniosix(); // 当前的协议类型；
        $result = FALSE;
        try {
            if (empty($gameOObject) || !$gameNo ||!$gameId) {
                throw new \Exception("当前游戏类Object，或游戏房间号异常!", BaseEnum::MSG_0XFA);
            }
            $getFiedKey = 'doNext';// 下注
            if($type == 2){
                $getFiedKey = 'doReNext';// 第二种
            }
            $fjDetail = BaseComm::distMemoryRooms($gameNo, FALSE);              // 房间内的信息；
            if (!$fjDetail || empty($fjDetail) || (isset($fjDetail[$getFiedKey]) && intval($fjDetail[$getFiedKey]) === 1)) { // 停掉标识；只接收一次操作
                BaseEnum::Logger("触发下一步结束：{$getFiedKey}  = 1, AND gameNo="  .$gameNo , 'user-login');
                return FALSE;
            }
            BaseEnum::Logger('执行下一步处理： (doNextStep)--->doNextPlayBets ==> ' . json_encode([
                "ID" => $gameNo,
                "TYPE" => $type,
                "doNext" => 1
            ]), 'user-login');
            
            //处理单个下一步内容：
            if (!method_exists($gameOObject, "doNextSteps")) {      // 玩家下注
                throw new \Exception("当前游戏类Object里的函数doNextSteps异常!", BaseEnum::MSG_0XFA);
            }
            
            //TODO 执行下一步操作
            // 示例： type=1 默认抢庄>>>下注;
            // (1) 执行方法: StartUserBetMuts($gameId,$gameRId,$gameNo,$players=false,$zjUserid= 0,$zjUserInfo = false,$useCards = FALSE)
            // (2) 组装对应的数据；启动下注倒计时功能；
            
            $result = $gameOObject -> doNextSteps($type,$loginFd, $gameNo, $fjDetail, $getUix);
            BaseEnum::Logger('执行下一步处理结果： (doNextStep)--->返回 ==> ' . json_encode($result), 'user-login');
            
        } catch (\Throwable $e) {
            BaseEnum::Logger("操作异常：" . $e->getMessage(), 'user-login');
            return TRUE;
        }
        return FALSE;
    }
    
    
    /**
     * TODO 玩家下注通用操作
     */
    public function playGameBets(){
        $getUix = $this->paramsBean->getUniosix();
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(TRUE);
        $gameOObject = $this->paramsBean->getGameObject();
        $roomId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0; // 房号
        $qmutil = isset($data['qmutil']) ? intval($data['qmutil']) : 0;         // 下注倍数
        
        $gameId = (!empty($roomId) && intval($roomId) >= 1000) ? intval($roomId/10): 0 ;
        $gameNo = isset($data['gameNo']) ? trim($data['gameNo']) : ""; // 房间编号
        BaseEnum::Logger("玩家操作:(下注)-Start--getUniosix={$getUix},RoomId={$roomId},gameNo={$gameNo},req_data=".json_encode($data), 'user-login');
        BaseEnum::Logger('实例化：整体 (getGameObject)--->>>' . json_encode($gameOObject), 'user-login');
        $playerInfo = $userId = FALSE; // 玩家登录信息
        try {
            //TODO 检查登录状态
            $playerInfo = $this->LoginPlayUser($userId);
            if (!$playerInfo || $userId <= 0 ) { return FALSE; }
            if (!$gameNo || ! $roomId || $qmutil <= 0) {
                throw new \Exception("提交参数异常!!", BaseEnum::MSG_0XF2);
            }
            $params = $data ;
            $params["loginUid"] = $userId;
            $params["loginFd"] = $loginFd;
            //TODO 下注开始(asycPlayBets)
            if (!$gameOObject || empty($gameOObject)) {
                $gameOObject = BaseEnum::getClassObject(FALSE,$gameId);                         // 创建对象；
            }
            
            if (!empty($gameOObject)) {
                $gameOObject->setGameStatus("P-" . CardEnum::GAME_STEP_2);                      // 设置游戏状态；
                BaseEnum::Logger("玩家下注处理，[{$roomId}]---->>>" . json_encode($gameOObject), 'user-login');
                if(method_exists($gameOObject, "asycPlayBets")) {   
                    //TODO 使用协程来下注
                    //go(function() use($gameOObject,$gameId,$roomId,$gameNo,$params,$userId,$playerInfo,$qmutil){
                        $errorNo = -1;
                        $resflag = $gameOObject -> asycPlayBets($roomId,$gameNo,$params,$errorNo);
                        BaseEnum::Logger("玩家下注处理结果：--->" . json_encode([$roomId,$resflag,$errorNo]), 'user-login');
                        if ($resflag === TRUE) {
                            $user = ['uid' => $userId,'username'=>$playerInfo['name']];
                            $extInfo = '';
                            if ($gameId == 105){
                                $seatName = [1=>'天',2=>'地',3=>'玄',4=>'黄'];
                                $seatName = (isset($params['seatNo']) && isset($seatName[$params['seatNo']])) ? $seatName[$params['seatNo']] : '';
                                $extInfo = !empty($seatName) ? "位置{$seatName}" : "";
                            }
                            $info = "玩家{$user['username']}在房间号{$roomId}游戏局{$gameNo}".$extInfo."中下注{$qmutil}倍";
                            BaseComm::userLogger($user,1,$info,'下注');
                            return FALSE;   //TODO 各自下注操作(默认成功)
                        }else{
                            $this->ResError($errorNo,"下注失败!");
                        }
                    //});
                }else{
                    throw new \Exception("下注类asycPlayBets异常!!", BaseEnum::MSG_0XFD);
                }
            } else {
                BaseEnum::Logger("下注失败：(playBetMoney)[{$roomId}]----失败!!!!" . json_encode($gameOObject), 'user-login');
                return FALSE;
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
        }
        return TRUE;
    }
    
    

    /**
     * 游戏前的准备工作；抢庄；和下注数；
     * 准备工作都做完就可以发牌操作；
     */
    public function playGameRush()
    {
        $betflag = 0; // FD； 抢庄对比；
        $loginFd = $this->paramsBean->getFd();
        $gameOObject = $this->paramsBean->getGameObject();
        BaseEnum::Logger('实例化：整体 (getGameObject)--->>>' . json_encode($gameOObject), 'user-login');
        $data = $this->paramsBean->getData(true);
        // 当前的协议类型；
        $getUix = $this->paramsBean->getUniosix();
        BaseEnum::Logger('玩家操作:Games-(gamehand)-Start--getUniosix====' . $getUix, 'user-login');
        $roomId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0; // 房号
        $gameNo = isset($data['gameNo']) ? trim($data['gameNo']) : ""; // 房间编号
        $gameMut = isset($data['qmutil']) ? intval($data['qmutil']) : 0; // 抢的倍数
        $allFd = false;
        $handler = "玩家抢庄"; // 抢庄指令；
        $playerInfo = $userid = FALSE; // 玩家登录信息
        try {
            $playerInfo = $this->LoginPlayUser($userid);
            if (!$playerInfo || $userid <= 0 ) { return FALSE; }
            if (! $gameNo || ! $roomId) {
                throw new \Exception("提交参数异常!!", BaseEnum::MSG_0XF2);
            }
            if (isset($getUix) && $getUix == BaseEnum::XYM_0X19) {
                $betflag = 1;
                $handler = "所有闲家下倍数"; // 闲家要组装订单信息，直接把订单写入DB；
            }

            // setLoopTimerStop
            $getTimer = PlayHelp::getInstance()->getCommTimerStop($gameNo);

            BaseEnum::Logger("定时器索引：-(gamehand)-获取是否要中断定时器=======[GET--Timer]---->>>" . $getTimer, 'user-login');
            $gamedata = false; // FD；当前房间是否在线并匹配成功；
            $roomStats = GameCommon::roomIsOpening($roomId, $gameNo, $getUix, $gamedata);
            
            BaseEnum::Logger($handler . '检测房间正常:-(gamehand - [' . $gameNo . '] Debug )--status==' . $roomStats . "==games=" . json_encode($gamedata), 'user-login');
            if (isset($roomStats) && $roomStats == 'OK' && ! empty($gamedata) && isset($gamedata['lists']) && ! empty($gamedata['lists'])) {
                $baseUser = $gamedata['lists']; // 所有玩家
                $allFd = array_column($baseUser, "fd", "seatNo");
                // 写redis
                $witeCash = GameCommon::playerGetMain($gameNo, $loginFd, $gameMut, $betflag, $allFd, $gameOObject); // 抢庄下倍数；
                BaseEnum::Logger($handler . ':执行操作：Games-(gamehand - [' . $gameNo . '--] 执行中.....(' . $gameMut . '倍))--betflag==' . $betflag . "====fd_seat=" . json_encode($allFd), 'user-login');
                // 发出抢的请求也要发给所有用户(协议XYM_0X18- 玩家抢庄)；
                $zjSeatid = ! empty($allFd) ? array_search($loginFd, $allFd) : 0;
                $showList = array(
                    "seatNo" => $zjSeatid,
                    "mutdotts" => $gameMut,
                    "p_fd" => $loginFd
                ); // 最大下注倍数

                // 下注成功|直接下注单DB写入;
                if ($witeCash === true) {
                    // 实时写入注单数据
                    BaseEnum::Logger('实时写入注单数据 : (gamehand - [' . $gameNo . '--' . $handler . '])--betflag==' . $getUix . "==fd_seat=" . json_encode($allFd), 'user-login');
                    if ($getUix == BaseEnum::XYM_0X18){
                        $user = ['uid'=>$userid,'username' => $playerInfo['name']];
                        $info = "玩家{$user['username']}在房间号{$roomId}游戏局{$gameNo}中抢庄{$gameMut}倍";
                        BaseComm::userLogger($user,0,$info,'抢庄');
                    }else if($getUix == BaseComm::XYM_0X19){
                        $user = ['uid'=>$userid,'username' => $playerInfo['name']];
                        $info = "玩家{$user['username']}在房间号{$roomId}游戏局{$gameNo}中下注{$gameMut}倍";
                        BaseComm::userLogger($user,0,$info,'下注');
                    }
                }
                AuthCommon::pushFrontWeb($allFd, json_encode([ "m" => $getUix, "data" => $showList ])); // 通知给所有玩家，谁在抢庄；
                return FALSE;
            } else if ($roomStats == 'NOT_BET' && $betflag === 1) { // 下注失败

                throw new \Exception("非法下注操作!!", BaseEnum::MSG_0XFD);
            } else {

                throw new \Exception("游戏数据异常!!", BaseEnum::MSG_0XFA);
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("操作异常：" . $e->getMessage(), 'user-login');
            $this->ResError($e->getCode(), $e->getMessage(),SysEnum::RETURN_MSG_LEVEL_1);
        }
        return true;
    }

    /**
     * 拼牌操作：提交拼牌的操作
     * 返回状态：完成
     */
    public function playSplit()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0; // 房间ID；
        $gameNo = isset($data['gameNo']) ? $data['gameNo'] : ""; // 游戏号；
        $seatNo = isset($data['seatNo']) ? intval($data['seatNo']) : - 1; // 座位号
        $cardValue = isset($data['cards']) ? $data['cards'] : FALSE; // 拼牌数据内容,用逗号分隔
        $allFds = [];
        // $nums = []; //拼牌计算 计算牌值：
        $playerInfo = $userid = FALSE; // 玩家登录信息
        try {
            
            $playerInfo = $this->LoginPlayUser($userid);
            if (!$playerInfo || $userid <= 0 ) { return FALSE; }
            
            if (! $gameRId || ! $gameNo || $seatNo < 0) {
                $this->ResError(BaseEnum::MSG_0XF2, "提交拼牌参数丢失");
                return true;
            }
            
            // 查询游戏数据；
            $gameData = BaseComm::distMemoryRooms($gameNo,FALSE);
            $userList = (isset($gameData['lists']) && ! empty($gameData['lists'])) ? $gameData['lists'] : false;
            if (! $gameData || ! $userList) {
                return false;
            }

            // 修改当前游局状态； ＝＝＝＝ 4 为拼牌中
            $gameData['fjStatus'] = CardEnum::GAME_STEP_4; // 修改为发牌成功；
            if (isset($gameData['lists']) && ! empty($gameData['lists'])) {
                $allFds = array_column($gameData['lists'], "fd", "seatNo");
                foreach ($gameData['lists'] as $setiid => $fg) {
                    if ($setiid >= 0 && $setiid === $seatNo) { // 当前玩家的座位号
                        $gameData['lists'][$setiid]["pstatus"] = CardEnum::GAME_STEP_4; // 玩家拼牌成功
                    }
                }
                BaseComm::distMemoryRooms($gameNo, TRUE,$gameData); // 保存用户数据
            }
            if (! empty($allFds)) {
                $data = [
                    "seatNo" => $seatNo,
                    "status" => 1,
                    "text" => "SUCCESS"
                ]; 
                // 推送给所有玩家，拼牌完成；
                AuthCommon::pushFrontWeb($allFds, json_encode([ 'm' => BaseEnum::XYM_0X21, "data" => $data ])); // 推送
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
        }
        return FALSE;
    }

    /**
     * 翻牌操作：提交翻牌的操作
     * 返回状态：完成
     */
    public function playFlip()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0; // 房间ID；
        $gameNo = isset($data['gameNo']) ? $data['gameNo'] : ""; // 游戏号；
        $playFds = [];
        $playerInfo = $userid = FALSE; // 玩家登录信息
        try {
            //TODO 登录验证
            $playerInfo = $this->LoginPlayUser($userid);
            if (!$playerInfo || $userid <= 0 ) { return FALSE; }
            
            
            if (! $gameRId || ! $gameNo) {
                $this->ResError(BaseEnum::MSG_0XF2, "提交翻牌参数丢失");
                return true;
            }
            // 查询游戏数据；
            $gameData = BaseComm::distMemoryRooms($gameNo,FALSE);
            $userList = (isset($gameData['lists']) && ! empty($gameData['lists'])) ? $gameData['lists'] : false;
            if (! $gameData || ! $userList) {
                return false;
            }
            if ($gameData['fjStatus'] != CardEnum::GAME_STEP_3){
                $this->ResError(BaseEnum::MSG_0XE4, "玩家非翻牌状态");
                return true;
            }
            $playFds = !empty($userList) ? array_column($userList, "fd","seatNo") : false ;
            $loginSeatNo = !empty($playFds) ? array_search($loginFd, $playFds) : -1; //登录用户所在位置；
            if ($loginSeatNo < 0) {
                $this->ResError(BaseEnum::MSG_0XF2, "提交翻牌参数丢失");
                return true;
            }
            $currUser = $userList[$loginSeatNo] ?? false;
            // 修改当前游局状态； ＝＝＝＝ 4 为翻牌中
            $gameData['fjStatus'] = CardEnum::GAME_STEP_4; // 修改为拼牌牌；
            $currUser['pstatus'] = CardEnum::GAME_STEP_4;
            $userList[$loginSeatNo] = $currUser;
            $gameData['lists'] = $userList;
            BaseComm::distMemoryRooms($gameNo, TRUE,$gameData); // 保存用户数据
            if (! empty($playFds)) {
                $data = [
                    "seatNo" => $loginSeatNo,
                    "cards" => $currUser['cards'],
                    "cardsLevel" => $currUser['cardsLevel'],
                    "cardsMutle" => $currUser['cardsMutle'],
                    "status" => 1,
                    "text" => "翻牌完成"
                ];
                // 推送给所有玩家，翻牌完成；
                AuthCommon::pushFrontWeb($playFds, json_encode([ 'm' => BaseEnum::XYM_0X26, "data" => $data ]));
            }
            $gameData = BaseComm::distMemoryRooms($gameNo,FALSE);
            $userList = (isset($gameData['lists']) && ! empty($gameData['lists'])) ? $gameData['lists'] : false;
            // 所有玩家都已经翻牌停掉定时器；
            $flipedSeat = [];
            foreach ($userList as $seatNo => $obj) {
                if (isset($obj['pstatus']) && intval($obj['pstatus']) == CardEnum::GAME_STEP_4) {
                    $flipedSeat[] = $seatNo;//已经翻牌的座位号
                }
            }
            if (!empty($flipedSeat) && sizeof($flipedSeat) == sizeof($userList)){
                PlayHelp::getInstance()->setCommTimerStop($gameNo,true);//所有玩家都已经翻牌停掉定时器
                BaseEnum::Logger("所有玩家翻牌完成", 'user-login');
            }

        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
        }
        return FALSE;
    }

    /**
     * 取消玩家匹配功能
     * 玩家加入匹配队表
     */
    public function playCancel()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        BaseEnum::Logger('玩家取消匹配：Games-(playCancel)-Start--------------gameRoomId==>' . $gameRId, 'user-login');
        // 查询FD对应的用户ID；
        $userid = 0;
        $playerInfo = FALSE; // 玩家登录信息
        try {
            //TODO 登录验证
            $playerInfo = $this->LoginPlayUser($userid);
            if (!$playerInfo || $userid <= 0 ) { return FALSE; }
            
            
            if (! $gameRId) {
                throw new \Exception("提交参数异常!!", BaseEnum::MSG_0XF2);
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
            return false;
        }
        //TODO 玩家取消加入列队处理；
        $joinList = BaseComm::distMemoryPlayer($gameRId, FALSE);
        if (!empty($joinList) && isset($userid) && intval($userid) > 0 && array_key_exists($userid, $joinList)) { // 主动退出
            unset($joinList[$userid]);
            BaseComm::distMemoryPlayer($gameRId,TRUE, $joinList); // 保存数据；
            BaseEnum::Logger("取消匹配：(playCancel)-Waiting == [房间ID：{$gameRId}],---(玩家主动取消匹配，删除列队的数据)------>>>>>" . json_encode($joinList), 'user-login');
            PlayHelp::getInstance()->setPlayerOpenHands($userid,"PLAY_CANCEL");     //玩家取消标识
            //TODO 清理玩家取消标识在内存里
            Timer::after(5000, function() use($userid,$gameRId){
                BaseEnum::Logger("8秒后内存取消数据自动销毁值：Waiting == [房间ID：{$gameRId}],---(清空 PlayCancel) 原来的值：value=". PlayHelp::getInstance()->getPlayerOpenHands($userid),'user-login');
                PlayHelp::getInstance()->setPlayerOpenHands($userid,FALSE);
            });
            $this->ResSUCCESS(BaseEnum::MSG_0XF,"成功"); // 自定义状态成功
        } else {
            $this->ResSUCCESS(BaseEnum::MSG_0XE0, "取消失败，继续游戏");
        }
        return TRUE;
    }

    /**
     * 游戏模拟发牌
     */
    public function opening()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameId = isset($data['gameId']) ? intval($data['gameId']) : 0;
        $gameNo = isset($data['gameNo']) ? $data['gameNo'] : "";
        if (! $gameId) {
            $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失",SysEnum::RETURN_MSG_LEVEL_1);
        } else {
            // 获取在线的游戏列表数据；XYM_0X17
            try {
                // 启动发牌；======> 操作代码 ： XYM_0X17；
                $useCards = GameCommon::createCardList($gameId, $gameNo, false);
                if (! $useCards || $gameId <= 0) {
                    $this->ResError(- 1, "暂无该游戏或没有可用房间");
                } else {
                    $this->ResOK($useCards, "生成棋牌成功");
                }
            } catch (\Throwable $e) {
                BaseEnum::Logger($e->getMessage(), 'user-login');
                return false;
            }
        }
        return TRUE;
    }

    /**
     * 玩家退出房间
     * 请求参数：{"m":34,"d":{"gameRoomId":"1010","gameNo":""}}
     */
    public function gameOver()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        $gameNo = isset($data['gameNo']) ? $data['gameNo'] : "";
        $gameId = isset($data['gameId']) ? $data['gameId'] : 0;
        if (! $gameRId || ! $gameNo)
            return FALSE;
        $userid = 0;
        $playerInfo = 0;
        try {
            //TODO 登录验证
            $playerInfo = $this->LoginPlayUser($userid);
            if (!$playerInfo || $userid <= 0 ) { return FALSE; }
            
            
            
            // 游戏状态判断，
            if ($gameId == 105){
                $gameData = BaseComm::distMemoryRooms($gameRId,FALSE);
                //玩家没有下注
                if (!empty($gameData)){
                    //百人牛牛清掉玩家列表
                    PlayBaiRen::doGameOutPlay($gameRId,$userid);
                }
            }else{
                $gameData = BaseComm::distMemoryRooms($gameNo, FALSE); // 游戏中的数据；
                if (! empty($gameData) && isset($gameData['fjStatus']) && intval($gameData['fjStatus']) === CardEnum::GAME_STEP_5) { // 退出成功；
                    RedisTools::Pool_hDel(SysEnum::USER_PLAY_FDMAP_KEY, $userid); // 退出房间；清掉玩家数据；
                    $this->ResSUCCESS(1, "退出成功"); // 自定义状态成功
                } else {
                    $this->ResError(BaseEnum::MSG_0XE0, "游戏正在进行中，不能退出");
                }
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
            return false;
        }
        return TRUE;
    }
    
    
    /**
     * TODO 游戏中的情况跳出页面
     */
    public function doGameOut(){
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        $gameId = isset($data['gameNo']) ? $data['gameNo'] : "";
        if (! $gameRId || !$gameId)  return FALSE;
        
        $userid = 0;
        $playerInfo = 0;
        try {
            //TODO  登录验证
            $playerInfo = $this->LoginPlayUser($userid);
            if (!$playerInfo || $userid <= 0 ) { return FALSE; }
            
            //TODO  游戏状态（有玩家离线出去）
            BaseEnum::Logger("玩家上下线：[loginFd = {$loginFd}]---loginUid : {$userid}  ==> gameNo : " .$gameId, 'user-login');
            RedisTools::Pool_hSet(SysEnum::USER_OUTPLAY_FDMAP_KEY, $loginFd , $userid);
            
            $this->ResSUCCESS(1, "玩家上/下线操作");
            return TRUE;
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
        }
        return FALSE;
    }
    

    
    /**
     * TODO 游戏通知数据
     * 异步主动请求的返回是是列表信息
     */
    public function doNotices() {
        $data = $this->paramsBean->getData(true);
        $gameId = isset($data['gameId']) ? intval($data['gameId']) : 0; // 传入房间ID；
        BaseEnum::Logger("获取公告：Games-(doNotices)-Start---[page=10条]---gameRoomId==>" . $gameId, 'user-login');
        
        $userid = FALSE; // TODO 玩家信息验证
        $playerInfo = $this->LoginPlayUser($userid);
        if (!$playerInfo || $userid <= 0 ) { return FALSE; }
        
        $result = PlayCommon::getNoticeCache($gameId);
        
        //查询当前游戏下的数据
        if(!empty($result)){
            $this->ResOK($result,"OK");
        }
        return FALSE;
    }


    /**
     * 玩家记录列表；
     * 请求参数：{"m":36,"d":{"gameId":"101","page":10}}
     */
    public function playOrder()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameId']) ? intval($data['gameId']) : 0; // 传入房间ID；
        $page = isset($data['page']) ? intval($data['page']) : 0; // 页码数
        if (! $page || $page < 0) $page = 10;
            
        BaseEnum::Logger("获取记录：Games-(playOrder)-Start---[page={$page}条]---gameRoomId==>" . $gameRId, 'user-login');
        $userid = 0;
        //TODO 登录验证
        $playerInfo = $this->LoginPlayUser($userid);
        if (!$playerInfo || $userid <= 0 ) { return FALSE; }
        

        // 取所有房间；
        $dbmodel = new GameType();
        $gameInfo = $dbmodel->getInfo($gameRId, true, [
            "roomId",
            "roomName",
            "status",
            'smallPoints',
            'everyPoints'
        ]); 
        $gameRooms = isset($gameInfo["rooms"]) ? $gameInfo["rooms"] : FALSE;    // 取一个数组；

        // 所有房间列表；
        $gameRooms = ! empty($gameRooms) ? array_column($gameRooms, "roomName", "roomId") : false;
        // 玩家操作数据；
        $orderList = GameCommon::getUserPlayOrder($userid, $gameRId, $page);
        $userOrders = [];
        if (isset($orderList) && !empty($orderList)) {     // 主动退出
            foreach ($orderList as $order) { // 订单数据===> 数据整合
                $roomId = isset($order['roomId']) ? intval($order['roomId']) : 0;
                // 房间ID；
                $neworder = array(
                    "gameId" => @$order['gameId'],
                    "gameNo" => @$order['gameNo'],
                    "roomName" => isset($gameRooms[$roomId]) ? $gameRooms[$roomId] : "", // 房间名
                    "userCount" => @$order['userCount'],
                    "cellScore" => isset($order['gameNo']) ? floatval($order['gameNo']) : 0.0,
                    "profit" => isset($order['profit']) ? floatval($order['profit']) : 0.0,
                    "gameStartTime" => @$order['gameStartTime'],
                    "gameEndTime" => @$order['gameEndTime']
                );
                $userOrders[] = $neworder;
            }
        } 
        $this->ResOK($userOrders, "获取记录成功"); // 获取游戏列表
        return TRUE;
    }

    /**
     * 玩家规则；
     * 请求参数：{"m":35,"d":{"gameId":"101","gameNo":""}}
     */
    public function gameRules()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameId = isset($data['gameId']) ? intval($data['gameId']) : 0;
        $rules = GameCommon::getGameRules($gameId);
        // 游戏记录；
        if (isset($rules) && ! empty($rules)) {
            $this->ResOK($rules, "获取成功");
        } else {
            $this->ResError(BaseEnum::MSG_0XF0, "暂无数据");
        }
        return TRUE;
    }
}